﻿#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
using namespace std;

class Person
{
public:
	Person(const char* name = "peter")
		: _name(name)
	{
		cout << "Person()" << endl;
	}

	Person(const Person& p)
		: _name(p._name)
	{
		cout << "Person(const Person& p)" << endl;
	}

	Person& operator=(const Person& p)
	{
		cout << "Person operator=(const Person& p)" << endl;
		if (this != &p)
			_name = p._name;

		return *this;
	}

	~Person()
	{
		cout << "~Person()" << endl;
	}
protected:
	string _name; // 姓名
};



class Student : public Person
{
public:
	// 默认成员函数 - 规则高度相似
	// 两份部分分开处理： 
	// 1.基类成员(看作整体,调用基类构造) 
	// 2.派生类成员(跟类和对象一样)

	Student(const char* name, int num, const char* addr)
		:Person(name) //显示调用（就像用匿名对象一样）
		, _num(num)
		, _addr(addr)
	{
		// 初始化列表的初始化顺序只与声明顺序有关
		// 因此会优先调用基类的构造，再对派生类的成员变量进行初始化
		// 一般都要自己写（因为要传参）
	}

	// 拷贝构造时，基类的部分调用基类自己的拷贝构造，派生类的按规则自己构造

	Student(const Student& s)
		:Person(s) //这里是指针和引用，不叫切片
		, _num(s._num)
		, _addr(s._addr)
	{
		//一般来说，不涉及深拷贝的话，编译器默认生成的就够用
	}

	Student& operator=(const Student& s)
	{
		//一般来说，不涉及深拷贝的话，编译器默认生成的就够用
		if (this != &s)
		{
			Person::operator=(s); //调用父类的赋值运算符重载
			_num = s._num;
			_addr = s._addr;
		}
		return *this;
	}

	// 析构函数的名字因为后续多态章节原因(重写)，
	// 会被处理为destructor
	// 所以派生类和基类的析构构成了隐藏关系
	// 因此只能用 基类::析构函数 来调用
	~Student()
	{
		//Person::~Person();
		// 派生类析构调用后，会自动调用父类析构，
		// 所以自己实现析构函数无需显式调用
		cout << "~Student()" << endl;
	} //自动调用父类，才能保证先子后父的析构顺序
	// 构造初始化：先父后子
	// 析构清资源：先子后父
	// 如果先析构父类，但是子类析构可以访问父类成员，此时容易产生非法访问

protected:
	int _num; //学号
	string _addr;
};

//int main()
//{
//	Student s1("Mike", 1, "US");
//	Student s2(s1);
//
//	/*Student s3("LiHua", 2, "CN");
//	s1 = s3;*/
//
//	return 0;
//}



// 实现一个不能被继承的类
// C++11的方法
class Base final
{
public:
	void func5() { cout << "Base::func5" << endl; }
protected:
	int a = 1;
private:
	// C++98的⽅法
	/*Base()
	{}*/
};

//class Derive :public Base //报错
//{
//	void func4() { cout << "Derive::func4" << endl; }
//protected:
//	int b = 2;
//};

int test()
{
	Base b;
	//Derive d;
	return 0;
}
